//
//  MultiThreadViewController.m
//  iOSCodeLearning
//
//  Created by Ace on 2017/11/23.
//  Copyright © 2017年 Ace. All rights reserved.
//

#import "MultiThreadViewController.h"
@interface MultiThreadViewController ()


@end

@implementation MultiThreadViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
   
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

//    [self p_NSThread];
//
    [self p_GCDBase];
//    [self p_GCDMainQueue];
//    [self p_GCDNormalUsing];
//    [self p_GCDGroup];
}
/**
 GCD 队列组的使用
 */
- (void)p_GCDGroup{
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    // 创建队列组
    dispatch_group_t group = dispatch_group_create();
//    // 队列组的使用方式 1
    dispatch_group_async(group, queue, ^{
        NSLog(@"对列组里面异步添加的第一个任务  %@" ,[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"对列组里面异步添加的第二个任务  %@" ,[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"对列组里面异步添加的第三个任务  %@" ,[NSThread currentThread]);
    });
    dispatch_group_notify(group, queue, ^{
        // 这个block 中的方法是在子线程中执行的
        NSLog(@"监听到队列组中的任务全部执行完毕了 %@",[NSThread currentThread]);
    });
    NSLog(@"end");
    
    // 队列组 使用方式2
    // 这个方法之后的异步任务都会被放到队列组中
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
         NSLog(@"对列组里面异步添加的第一个任务  %@" ,[NSThread currentThread]);
        // 通过这种方式添加任务到队列组里，需要在任务执行完毕以后将其移除队列组
        dispatch_group_leave(group);
    });

    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"对列组里面异步添加的第二个任务  %@" ,[NSThread currentThread]);
        dispatch_group_leave(group);
    });

    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"对列组里面异步添加的第三个任务  %@" ,[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    // 等待 知道队列组里面的所有的任务都执行完毕了才会执行
    // 这个方法本身是阻塞的，执行完毕了才会执行后面的方法
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"end");
    
    

}
#pragma mark - GCD 的常用方法

/**
 GCD 中的常用方法
 */
- (void)p_GCDNormalUsing{
    
//    // 1 延时
    //1.1> 延时的第一种方法 : 延时两秒执行 dealyTask 方法
//    [self performSelector:@selector(dealyTask) withObject:nil afterDelay:2];
//
//    //1.2> 延时的第二种方法：延时两秒执行block 中的方法
//    [NSTimer scheduledTimerWithTimeInterval:2 repeats:NO block:^(NSTimer * _Nonnull timer) {
//        NSLog(@"延时的第二种方法：NSTimer");
//    }];
//
//    //1.3> 延时的第三种方法 ：GCD
//    // 主队列
//    dispatch_queue_t queue = dispatch_get_main_queue();
//    // 全局并发队列
//    dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//    // 传入的参数 queue 如果是主队列则 block 中的代码会在主线程中执行
//    // 如果是 全局并发队列 ，则会在子线程中执行
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)),queue, ^{
//
//        NSLog(@"第三种延时方法GCD:%@",[NSThread currentThread]);
//
//    });
    
    // 2 一次性代码
    /*
     注意： 整个应用程序 只会执行一次，所以不能放在懒加载中
     */
    
//    static dispatch_once_t onceToken;
//    dispatch_once(&onceToken, ^{
//        NSLog(@"一次性代码");
//    });

    // 3 GCD 中的栅栏函数
//     全局并发队列 （官方规定了 栅栏函数不能 在全局并发队列中执行）
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//     创建一个普通的 并发队列
//    dispatch_queue_t queue = dispatch_queue_create("wcc", DISPATCH_QUEUE_CONCURRENT);
//    dispatch_async(queue, ^{
//        NSLog(@"downLoad1 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_async(queue, ^{
//        NSLog(@"downLoad2 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_barrier_async(queue, ^{
//        NSLog(@"+++++++++++++++++++++%@",[NSThread currentThread]);
//    });
//
//    dispatch_async(queue, ^{
//        NSLog(@"downLoad3 ---------%@",[NSThread currentThread]);
//    });
//
    
    

    // GCD 的快速遍历
    // 传入的参数 queue 只能穿入并发队列 block 中的代码在 子线程中执行
    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {

        NSLog(@"%ld  %@",index,[NSThread currentThread]);

    });

    NSLog(@"遍历全部执行结束");

}



- (void)dealyTask{
    
    NSLog(@"%s",__func__);
    
}

# pragma mark - GCD 中的主队列
/**
 GCD 中的主队列
 */
- (void)p_GCDMainQueue{
    
    // 异步函数 + 主队列
//    dispatch_queue_t queue = dispatch_get_main_queue();
//
//    dispatch_async(queue, ^{
//        NSLog(@"downLoad1 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_async(queue, ^{
//        NSLog(@"downLoad2 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_async(queue, ^{
//        NSLog(@"downLoad3 ---------%@",[NSThread currentThread]);
//    });
//
    // 同步函数 + 主队列
//    dispatch_queue_t queue = dispatch_get_main_queue();
//    
//    dispatch_sync(queue, ^{
//        // 任务A
//        NSLog(@"downLoad1 ---------%@",[NSThread currentThread]);
//    });
//    // 任务 B
//    NSLog(@"end");
}

#pragma mark - GCD 的基本用法
/**
 GCD 的基本用法
 */
- (void)p_GCDBase{
    
    // 异步函数 + 并发队列: 开启多个线程，队列里面的任务并发执行
//    dispatch_queue_t queue = dispatch_queue_create("wcc", DISPATCH_QUEUE_CONCURRENT);
//
//    dispatch_async(queue, ^{
//
//        NSLog(@"downLoad1 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_async(queue, ^{
//
//        NSLog(@"downLoad2 ---------%@",[NSThread currentThread]);
//
//    });
//
//    dispatch_async(queue, ^{
//
//        NSLog(@"downLoad3 ---------%@",[NSThread currentThread]);
//
//    });
    
    // 异步函数 + 穿行队列 : 开启一条子线程 ，线程中的任务是串行执行的
//    dispatch_queue_t queue =dispatch_queue_create("wcc1", DISPATCH_QUEUE_SERIAL);
//
//    dispatch_async(queue, ^{
//         NSLog(@"downLoad1 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_async(queue, ^{
//        NSLog(@"downLoad2 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_async(queue, ^{
//        NSLog(@"downLoad3 ---------%@",[NSThread currentThread]);
//    });
    
//
    dispatch_queue_t queue = dispatch_queue_create("11", DISPATCH_QUEUE_SERIAL);

    for (NSInteger i= 0; i<10; i++) {

        dispatch_async(queue, ^{

            for (NSInteger j= 0; j<100; j++) {
                NSLog(@"%ld--------------%@",i,[NSThread currentThread]);
            }
        });
    }
    
    
    // 同步函数 + 并发队列：不开线程 任务串行执行
//    dispatch_queue_t queue = dispatch_queue_create("wcc2",DISPATCH_QUEUE_CONCURRENT);
//
//    dispatch_sync(queue, ^{
//        NSLog(@"downLoad1 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_sync(queue, ^{
//         NSLog(@"downLoad2 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_sync(queue, ^{
//        NSLog(@"downLoad3 ---------%@",[NSThread currentThread]);
//    });
    // 同步函数 + 串行队列： 不开线程 ，任务串行执行
//    dispatch_queue_t queue = dispatch_queue_create("wcc3", DISPATCH_QUEUE_SERIAL);
//
//    dispatch_sync(queue, ^{
//         NSLog(@"downLoad1 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_sync(queue, ^{
//         NSLog(@"downLoad2 ---------%@",[NSThread currentThread]);
//    });
//
//    dispatch_sync(queue, ^{
//         NSLog(@"downLoad3 ---------%@",[NSThread currentThread]);
//    });
    
}
#pragma mark - NSThread 的基本用法
/**
 NSThred 创建线程
 使用快捷 但是无法对线程进行详细的设置
 */
- (void)p_NSThread{
    
    // 1 直接创建
    NSThread *threadA = [[NSThread alloc]initWithBlock:^{
        NSLog(@"threadA :%@",[NSThread currentThread]);
    }];
    // 设置线程的优先级 （线程有限级别为0.0 ~ 1.0 ，子线程默认优先级是0.5）
    threadA.threadPriority = 1.0;
    [threadA start];
    
    // 2 类方法分离线程
    [NSThread detachNewThreadWithBlock:^{
        NSLog(@"分离线程 %@",[NSThread currentThread]);
    }];
    
    // 3 开启后台线程
    [self performSelectorInBackground:@selector(bgThread:) withObject:nil];
    
    
    // 回到主线程 waitUntilDone 这参数代表是否等待bgThread 方法结束之后，再执行之后的操作
    [self performSelectorOnMainThread:@selector(bgThread:) withObject:nil
                      waitUntilDone:YES];
    // 回到指定线程
    [self performSelector:@selector(bgThread:) onThread:threadA withObject:nil
            waitUntilDone:YES];
    
    
}

- (void)bgThread:(NSObject *)obj{
    NSLog(@"开启后台线程");
    
    // 阻塞线程
    [NSThread sleepForTimeInterval:2];

    for (NSInteger i = 0; i<100; i++) {
        
        NSLog(@"%zd",i);
        if (i == 20) {
            [NSThread exit]; // 代表 强制退出当前线程
            break;           // 代表 线程执行完毕，自动进入死亡状态
        }
        
    }
}





@end
